package com.example.myapplication.tools;

import android.os.Handler;
import android.os.Message;
import android.util.Log;

import androidx.annotation.NonNull;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class SocketTools {

    boolean isConnect = false;
    private Socket clisoc;
    private OutputStream outtoserver;
    private PrintWriter out;
    private BufferedReader reader;
    ReadMessage readMessage;
    String ip;
    int port;
    String lastSendInfo = "";
    int nullTimes = 0;
    int maxNull = 5;
    List<String> messageList;
    boolean isSending = false;
    TimeUtils2 timeUtils;
    String lastSendContent = "";

    /**
     * socket客户端类构造方法
     * @param _ip
     * @param _port
     * @param _readMessage
     */
    public SocketTools(String _ip, int _port, ReadMessage _readMessage){
        ip = _ip;
        port = _port;
        readMessage = _readMessage;
        messageList = new ArrayList<>();
        timeUtils = new TimeUtils2(3000,3000,()->{
            isSending = false;
            lastSendContent = "";
        });
    }

    private void closeTime(){
        if(timeUtils != null && timeUtils.isRun){
            timeUtils.cancle();
        }
    }

    public boolean createSocket(String sendInfo){
        try {
            //输出流区
            clisoc=new Socket(ip,port);
            clisoc.setKeepAlive(true);
            outtoserver=clisoc.getOutputStream();
            out = new PrintWriter(clisoc.getOutputStream());
            //输入流区
            InputStream inFromServer = clisoc.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inFromServer,"UTF-8"));//

            read();
            if(sendInfo != null && sendInfo.length() > 0){
                lastSendInfo = sendInfo;
            }
            isSending = false;
            closeTime();
            if(lastSendInfo.length() > 0){
                try {
//                    out.write(lastSendInfo);
//                    out.flush();
                    outtoserver.write(lastSendInfo.getBytes("UTF-8"));
                    outtoserver.flush();
                }catch(Exception e) {
                    System.out.println("socket~client新建连接并发送失败:" + e);
                    Message msg = new Message();
                    msg.what = 1;
                    msg.obj = lastSendInfo;
                    handlerReCreate.sendMessage(msg);
                }
                lastSendInfo = "";
            }
            isConnect = true;
            return true;
        }catch(IOException e) {
            lastSendInfo = "";
            System.out.println("socket~client创建失败:"+e);
            isConnect = false;
            readMessage.error("创建失败");
            return false;
        }
    }

    Handler handlerReCreate = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            isSending = false;
            closeTime();
            switch (msg.what){
                case 0:
                    new Thread(){
                        @Override
                        public void run() {
                            close();
                            boolean isCreate = createSocket("");
                        }
                    }.start();
                    break;
                case 1:
                    new Thread(){
                        @Override
                        public void run() {
                            close();
                            boolean isCreate = createSocket("");
                            if(!isCreate && !"test".equals(lastSendInfo)){
                                String temp = StringUtils.transString(msg.obj);
                                readMessage.error(temp);
                            }
                        }
                    }.start();
                    break;
                case 2:
                    if(timeUtils != null && !timeUtils.isRun){
                        timeUtils.RunTimer();
                    }
                    break;
            }
        }
    };

    /**
     * socket客户端类发送消息方法
     * @param msg
     */
    public void send(String msg) {
        if (StringUtils.transString(msg).length() > 0 && !messageList.contains(msg)) {// && !"test\r\n".equals(msg)
            messageList.add(msg);
        }
        if(messageList.size() >= 2 && messageList.get(0).contains("test")){
            messageList.remove(0);
            isSending = false;
        }
        sendMessage();
    }

    private synchronized void sendMessage(){
        if(isSending){
            return;
        }
        if(messageList.size() >0){
            String sendMsg = messageList.get(0);
            if(lastSendContent.equals(sendMsg)) {
                if(!sendMsg.contains("test")){
                    return;
                }
            }else{
                lastSendContent = sendMsg;
            }
        }else{
            return;
        }
        new Thread(){
            @Override
            public void run() {
                try {
                    if(messageList.size() >0){
                        String sendMsg = messageList.get(0);
                        if(sendMsg.length() > 0 && !sendMsg.startsWith("test")){
                            lastSendInfo = sendMsg;
                        }else{
                            lastSendInfo = "test";
                        }
                        if(!isConnect){
                            Message msg = new Message();
                            msg.what = 1;
                            handlerReCreate.sendMessage(msg);
                            return;
                        }
                        Log.e("SocketTools ===>> ","发送数据 : " + sendMsg);
                        try {
                            clisoc.sendUrgentData(0xFF);
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                            Log.e("SocketTools ===>> ", "socket~client发送失败 sendUrgentData(0xFF)");
                            Message msg = new Message();
                            msg.what = 1;
                            handlerReCreate.sendMessage(msg);
                            isSending = false;
                            closeTime();
                        }
//                        out.write(sendMsg.getBytes(StandardCharsets.UTF_8));
//                        out.flush();
                        outtoserver.write(sendMsg.getBytes("UTF-8"));
                        outtoserver.flush();
                        handlerReCreate.sendEmptyMessage(2);
                        isSending = true;
                        lastSendInfo = "";
                    }
                }catch(Exception e) {
                    isConnect = false;
                    System.out.println("socket~client发送失败:"+e);
                    Message msg = new Message();
                    msg.what = 1;
                    handlerReCreate.sendMessage(msg);
                    isSending = false;
                    closeTime();
                }
            }
        }.start();
    }

    /**
     * socket客户端类读取消息方法
     */
    public void read() {
        Readthread rt=new Readthread();
        rt.start();
    }


    /**
     * socket客户端读取线程类
     * @author Administrator
     *
     */
    public class Readthread extends Thread{
        boolean isRun = true;
        public void run() {
            while(isRun)
            {
                try {
                    if(reader !=null){
                        String result = reader.readLine();
                        //System.out.println("socket~client收到消息:"+tempstr);
                        //调用主类读取中断方法
                        if(result == null){
                            isRun = false;
                            nullTimes ++;
                            if(maxNull == nullTimes){
                                messageList.clear();
                                lastSendContent = "";
                                isSending = false;
                                Message msg = new Message();
                                msg.what = 0;
                                handlerReCreate.sendMessage(msg);
                                nullTimes = 0;
                            }else{
                                read();
                            }
                            Log.e("socketTools ===>> ","返回数据 : 返回null次数" + nullTimes);
                        }else{
                            if(messageList != null && messageList.size() >0){
                                messageList.remove(0);
                                lastSendContent = "";
                                isSending = false;
                                sendMessage();
                            }
                            Log.e("SocketTools ===>> ","返回数据 : " + result);
                            readMessage.message(result);
                            nullTimes = 0;
                        }
                    }else{
                        isRun = false;
                    }

                }catch(IOException e) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException ee) {
                        ee.printStackTrace();
                    }
                }
            }
        }
    }


    /**
     * socket客户端类关闭方法
     */
    public void close() {
        new Thread(){
            @Override
            public void run() {
                try {
                    if(out != null){
                        out.close();
                        out = null;
                    }
                    if(reader != null){
                        reader.close();
                        reader = null;
                    }
                    if(outtoserver != null){
                        outtoserver.close();
                        outtoserver = null;
                    }
                    if(clisoc != null){
                        clisoc.close();
                        clisoc = null;
                    }

                }catch(IOException e) {
                    System.out.println("socket~client关闭失败:"+e);
                }
            }
        }.start();

    }

    public interface ReadMessage {
        void message(String msg);
        void error(String errorInfo);
    }

}